package es.ceura.wilder.handlers;

import es.ceura.wilder.actions.Action;
import es.ceura.wilder.actions.UnsuportedActionException;
import es.ceura.wilder.configuration.Config;
import es.ceura.wilder.controllers.ActionController;
import es.ceura.wilder.controllers.Register;
import es.ceura.wilder.datastructures.Cookie;
import es.ceura.wilder.datastructures.request.HTTPRequest;
import es.ceura.wilder.datastructures.Header;
import es.ceura.wilder.datastructures.HeaderType;
import es.ceura.wilder.logger.Logger;
import es.ceura.wilder.datastructures.Message;
import es.ceura.wilder.parsers.CookieParser;
import es.ceura.wilder.parsers.HTTPRequestParser;
import es.ceura.wilder.parsers.InvalidHTTPRequestException;
import es.ceura.wilder.resources.DeniedAccesException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.Set;

/**
 *
 * @author Jorge Madrid
 */
public class RequestHandler implements Runnable {

    private Socket clientSocket;
    private MessageReciever reciever;
    private Logger logger;
    private HTTPRequestParser parser;
    private ActionController actionController;
    private CookieParser cookieParser;

    public RequestHandler(Socket clientSocket) {
        this.clientSocket = clientSocket;
        this.reciever = new MessageReciever();
        this.cookieParser = new CookieParser();
        logger = Logger.INSTANCE;
        parser = new HTTPRequestParser();
        actionController = Register.INSTANCE.getActionController();
    }

    @Override
    public void run() {
        HTTPRequest request;
        try {
            int timeout = Integer.parseInt(Config.INSTANCE.getConfigVar(Config.TIMEOUT));
            clientSocket.setSoTimeout(timeout);


            String httpBody = reciever.recieveHTTPData(clientSocket);
            request = parser.parseHTTPRequest(httpBody);

            System.out.println("request = " + request);

            Message message = reciever.recieveMessage(clientSocket, getMessageSize(request));
            final String messageString = new String(message.toArray());
            request.setMessage(messageString);

            System.out.println("message = " + messageString);

            Set<Cookie> cookies = cookieParser.getCookies(request);
            
            for (Cookie cookie : cookies) {
                System.out.println(cookie);
            }

            Action action = actionController.getAction(request.getHttpMethod());
            action.doAction(request, clientSocket);


        } catch (UnsuportedActionException ex) {
            logger.logError("Action requested not supported by server: " + clientSocket, ex);
        } catch (DeniedAccesException ex) {
            logger.logError("Access denied..." + clientSocket, ex);
        } catch (InvalidHTTPRequestException ex) {
            logger.logError("HTTPRequest was invalid..." + clientSocket, ex);
        } catch (SocketException ex) {
            logger.logError("", ex);
        } catch (IOException ex) {
            logger.logError("", ex);
        } finally {
            closeClientSocket();
        }
    }

    private int getMessageSize(HTTPRequest request) throws InvalidHTTPRequestException {
        Header contentLength = request.getHeaderValue(HeaderType.CONTENT_LENGTH);

        if (contentLength == null) {
            contentLength = new Header("0");
            request.putHeader(HeaderType.CONTENT_LENGTH, contentLength);
        }
        return Integer.parseInt(contentLength.getValue());
    }

    public final void closeClientSocket() {
        InputStream input = null;
        OutputStream outputStream = null;
        try {
            input = clientSocket.getInputStream();
            outputStream = clientSocket.getOutputStream();
        } catch (IOException ex) {
            logger.logError("Error al cerrrar conexiones del socket: " + clientSocket, ex);
        } finally {

            if (input != null) {
                try {
                    input.close();
                } catch (IOException ex) {
                    logger.logError("Error al cerrrar conexiones del socket: " + clientSocket, ex);
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException ex) {
                    logger.logError("Error al cerrrar conexiones del socket: " + clientSocket, ex);
                }
            }
            if (clientSocket != null) {
                try {
                    clientSocket.close();
                } catch (IOException ex) {
                    logger.logError("Error al cerrrar conexiones del socket: " + clientSocket, ex);
                }
            }

        }
    }
}
